package handler

import (
	"bytes"
	"errors"
	"github.com/go-playground/locales/zh"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	"github.com/zeromicro/go-zero/core/logx"
	"net/http"
	"strings"
	"sync"
	common "zhongxc.cc/admin-common"
	"zhongxc.cc/admin-common/errs"
	"zhongxc.cc/admin-user-api/internal/types"

	zhtranslations "github.com/go-playground/validator/v10/translations/zh"
	captcha "github.com/mojocn/base64Captcha"
	"github.com/zeromicro/go-zero/rest/httpx"
	"zhongxc.cc/admin-user-api/internal/logic"
	"zhongxc.cc/admin-user-api/internal/svc"
)

var rwlock sync.RWMutex

type UserHandler struct {
	svcCtx *svc.ServiceContext
}

// 验证码的共享存储
var store = captcha.DefaultMemStore

func NewDriver() *captcha.DriverString {
	driver := new(captcha.DriverString)
	driver.Height = 38
	driver.Width = 120
	driver.NoiseCount = 5
	driver.ShowLineOptions = captcha.OptionShowSineLine | captcha.OptionShowSlimeLine | captcha.OptionShowHollowLine
	driver.Length = 4
	driver.Source = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
	driver.Fonts = []string{"wqy-microhei.ttc"}
	return driver
}

func NewUserHandler(svcCtx *svc.ServiceContext) *UserHandler {
	return &UserHandler{
		svcCtx: svcCtx,
	}
}

// GenerateCaptchaHandle
// @Description: 生成图形验证码
// @receiver u
// @param w
// @param r
func (u *UserHandler) GenerateCaptchaHandle(w http.ResponseWriter, r *http.Request) {
	// uuid := r.URL.Query().Get("uuid")
	// logx.Info("uuid=", uuid)
	var inReq struct {
		Uuid string `form:"uuid"`
	}
	err := httpx.ParseForm(r, &inReq)
	if err != nil {
		logx.Error(err)
	} else {
		logx.Info(inReq.Uuid)
	}
	var driver = NewDriver().ConvertFonts()
	c := captcha.NewCaptcha(driver, store)
	_, content, answer := c.Driver.GenerateIdQuestionAnswer()
	w.Header().Set("id", inReq.Uuid)
	item, _ := c.Driver.DrawCaptcha(content)
	_ = c.Store.Set(inReq.Uuid, strings.ToLower(answer))
	_, _ = item.WriteTo(w)
}

// CaptchaVerifyHandle
// @Description: 验证码校验
// @receiver u
// @param w
// @param r
func (u *UserHandler) CaptchaVerifyHandle(w http.ResponseWriter, r *http.Request) {
	_ = r.ParseMultipartForm(10 << 20) // multipart/form-data && application/x-www-form-urlencoded
	// _ = r.ParseForm()	// 解析 application/x-www-form-urlencoded

	uuid := r.PostForm.Get("uuid")
	code := r.PostForm.Get("code")
	logx.Infof("uuid=%s, code=%s\n", uuid, code)
	if store.Verify(uuid, strings.ToLower(code), true) {
		httpx.OkJsonCtx(r.Context(), w, common.NewResult().Deal(nil, nil))
		return
	}
	httpx.OkJsonCtx(r.Context(), w, common.NewResult().Deal(nil, errors.New("验证码错误")))
}

func (u *UserHandler) Login(w http.ResponseWriter, r *http.Request) {
	var req types.LoginRequest
	if err := httpx.ParseForm(r, &req); err != nil {
		httpx.ErrorCtx(r.Context(), w, err)
		return
	}

	uni := ut.New(zh.New())
	trans, _ := uni.GetTranslator("zh")
	v := validator.New()
	err := zhtranslations.RegisterDefaultTranslations(v, trans)
	if err != nil {
		logx.Error(err)
	}
	err = v.StructCtx(r.Context(), req)
	if err != nil {
		var invalid *validator.InvalidValidationError
		ok := errors.As(err, &invalid)
		if ok {
			logx.Error("param error: ", invalid)
			httpx.OkJsonCtx(r.Context(), w, common.NewResult().Deal(req, invalid))
			return
		}
		var buffer bytes.Buffer
		for _, err := range err.(validator.ValidationErrors) {
			logx.Error(err.Translate(trans))
			buffer.WriteString(err.Translate(trans))
			buffer.WriteString(",")
		}
		errorMsg := buffer.String()
		errorMsg = errorMsg[:len(errorMsg)-1]
		httpx.OkJsonCtx(r.Context(), w, common.NewResult().Deal(req, errors.New(errorMsg)))
		return
	}

	// 校验验证码
	if !store.Verify(req.Uuid, strings.ToLower(req.Code), true) {
		httpx.OkJsonCtx(r.Context(), w, common.NewResult().Deal(nil, errors.New("验证码错误")))
		return
	}

	// 登录
	loginLogic := logic.NewLoginLogic(r.Context(), u.svcCtx)
	resp, err := loginLogic.Login(&req)
	code, msg := errs.ParseGrpcError(err)

	httpx.OkJsonCtx(r.Context(), w, common.NewResult().Ok(resp, code, errors.New(msg)))
}

func (u *UserHandler) Info(w http.ResponseWriter, r *http.Request) {
	var req types.InfoRequest
	if err := httpx.ParseForm(r, &req); err != nil {
		httpx.ErrorCtx(r.Context(), w, err)
		return
	}

	result := common.NewResult()

	l := logic.NewUserLogicLogic(r.Context(), u.svcCtx)
	resp, err := l.Info(r.Context(), &req)
	code, msg := errs.ParseGrpcError(err)
	httpx.OkJsonCtx(r.Context(), w, result.Ok(resp, code, errors.New(msg)))
}
